﻿using System;
using System.Linq.Expressions;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.IO.Pipes;
using System.Reflection;
using System.Runtime.InteropServices;
using System.IO.MemoryMappedFiles;
using Microsoft.Win32.SafeHandles;
using System.Threading;
#if !NETCOREAPP
using System.IO.Ports;
#endif

namespace Go
{
    static class TypeReflection
    {

#if NETCOREAPP
        public static readonly Assembly _systemSocketAss = Assembly.LoadFrom(RuntimeEnvironment.GetRuntimeDirectory() + "System.Net.Sockets.dll");
        public static readonly Assembly _systemPipeAss = Assembly.LoadFrom(RuntimeEnvironment.GetRuntimeDirectory() + "System.IO.Pipes.dll");
#else
        public static readonly Assembly _systemAss = Assembly.LoadFrom(RuntimeEnvironment.GetRuntimeDirectory() + "System.dll");
        public static readonly Assembly _systemCoreAss = Assembly.LoadFrom(RuntimeEnvironment.GetRuntimeDirectory() + "System.Core.dll");
#endif
        public static MethodInfo GetMethod(Type type, string name, Type[] parmsType = null)
        {
            MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
            for (int i = 0; i < methods.Length; i++)
            {
                if (methods[i].Name == name)
                {
                    if (null == parmsType)
                    {
                        return methods[i];
                    }
                    else
                    {
                        ParameterInfo[] parameters = methods[i].GetParameters();
                        if (parameters.Length == parmsType.Length)
                        {
                            int j = 0;
                            for (; j < parmsType.Length && parameters[j].ParameterType == parmsType[j]; j++) { }
                            if (j == parmsType.Length)
                            {
                                return methods[i];
                            }
                        }
                    }
                }
            }
            return null;
        }

        public static FieldInfo GetField(Type type, string name)
        {
            FieldInfo[] members = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
            for (int i = 0; i < members.Length; i++)
            {
                if (members[i].Name == name)
                {
                    return members[i];
                }
            }
            return null;
        }

        public static Delegate CreateCall<Delegate>(Type objType, string name, Type[] paramsType)
        {
            MethodInfo methodInfo = GetMethod(objType, name, paramsType);
            int ins = methodInfo.IsStatic ? 0 : 1;
            var arguments = typeof(Delegate).GetGenericArguments();
            var paramTypes = methodInfo.GetParameters();
            var expressions = new LinkedList<Expression>();
            var argsParams = new ParameterExpression[ins + paramTypes.Length];
            var fixedObjs = new ParameterExpression[paramTypes.Length];
            if (!methodInfo.IsStatic)
            {
                argsParams[0] = Expression.Parameter(arguments[0]);
            }
            for (int i = 0; i < paramTypes.Length; i++)
            {
                Type paramType = paramTypes[i].ParameterType;
                fixedObjs[i] = Expression.Variable(paramType);
                argsParams[ins + i] = Expression.Parameter(arguments[ins + i]);
                expressions.AddLast(Expression.Assign(fixedObjs[i], Expression.Convert(argsParams[ins + i], paramType)));
            }
            var callExp = methodInfo.IsStatic ? Expression.Call(methodInfo, fixedObjs) : Expression.Call(Expression.Convert(argsParams[0], objType), methodInfo, fixedObjs);
            if (methodInfo.ReturnType == typeof(void))
            {
                expressions.AddLast(callExp);
            }
            else
            {
                expressions.AddLast(Expression.Convert(callExp, arguments[arguments.Length - 1]));
            }
            return Expression.Lambda<Delegate>(Expression.Block(fixedObjs, expressions), argsParams).Compile();
        }

        public static Delegate CreateCallNoCvt<Delegate>(Type objType, string name, Type[] paramsType)
        {
            MethodInfo methodInfo = GetMethod(objType, name, paramsType);
            int ins = methodInfo.IsStatic ? 0 : 1;
            var paramTypes = methodInfo.GetParameters();
            var invokeMethod = typeof(Delegate).GetMethod("Invoke");
            var parameters = invokeMethod.GetParameters();
            var argsParams = new ParameterExpression[ins + paramTypes.Length];
            var fixedObjs = new ParameterExpression[paramTypes.Length];
            if (!methodInfo.IsStatic)
            {
                argsParams[0] = Expression.Parameter(parameters[0].ParameterType);
            }
            for (int i = 0; i < paramTypes.Length; i++)
            {
                Type paramType = parameters[ins + i].ParameterType;
                fixedObjs[i] = argsParams[ins + i] = Expression.Parameter(paramType);
            }
            var callExp = methodInfo.IsStatic ? Expression.Call(methodInfo, fixedObjs) : Expression.Call(Expression.Convert(argsParams[0], objType), methodInfo, fixedObjs);
            return Expression.Lambda<Delegate>(Expression.Block(callExp), argsParams).Compile();
        }

        public static Delegate CreateNew<Delegate>(Type type)
        {
            var arguments = typeof(Delegate).GetGenericArguments();
            var paramTypes = new Type[arguments.Length - 1];
            Array.Copy(arguments, 0, paramTypes, 0, paramTypes.Length);
            var paramObjs = new ParameterExpression[paramTypes.Length];
            for (int i = 0; i < paramTypes.Length; i++)
            {
                paramObjs[i] = Expression.Parameter(paramTypes[i]);
            }
            var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, paramTypes, null);
            var newBody = Expression.New(constructor, paramObjs);
            return Expression.Lambda<Delegate>(newBody, paramObjs).Compile();
        }

        public static Func<T, R> CreateObjectGetter<T, R>(string name)
        {
            var fieldInfo = GetField(typeof(T), name);
            var paramObj = Expression.Parameter(typeof(T));
            var interField = Expression.Field(fieldInfo.IsStatic ? null : paramObj, fieldInfo);
            return Expression.Lambda<Func<T, R>>(interField, paramObj).Compile();
        }

        public static Action<T, object> CreateObjectSetter<T>(string name)
        {
            var fieldInfo = GetField(typeof(T), name);
            var paramObj = Expression.Parameter(typeof(T));
            var value = Expression.Parameter(typeof(object));
            var setField = Expression.Assign(Expression.Field(fieldInfo.IsStatic ? null : paramObj, fieldInfo), Expression.Convert(value, fieldInfo.FieldType));
            return Expression.Lambda<Action<T, object>>(setField, paramObj, value).Compile();
        }

        public static Action<object, object> CreateObjectSetter(Type objType, string name)
        {
            var fieldInfo = GetField(objType, name);
            Type fieldType = fieldInfo.FieldType;
            var paramObj = Expression.Parameter(typeof(object));
            var fixedObj = Expression.Variable(objType);
            var valueObj = Expression.Parameter(typeof(object));
            var cvtExp = fieldInfo.IsStatic ? null : Expression.Assign(fixedObj, Expression.Convert(paramObj, objType));
            var interField = Expression.Field(cvtExp, fieldInfo);
            Expression setField = Expression.Assign(interField, Expression.Convert(valueObj, fieldType));
            var setFieldBody = Expression.Block(new ParameterExpression[] { fixedObj }, setField);
            return Expression.Lambda<Action<object, object>>(setFieldBody, paramObj, valueObj).Compile();
        }
    }

    public struct socket_result
    {
        public bool success;
        public int size;
        public System.Exception ec;

        public socket_result(bool success = false, int size = 0, System.Exception ec = null)
        {
            this.success = success;
            this.size = size;
            this.ec = ec;
        }

        public string message
        {
            get
            {
                return null != ec ? ec.Message : null;
            }
        }

        static public implicit operator bool(socket_result src)
        {
            return src.success;
        }

        static public implicit operator int(socket_result src)
        {
            return src.size;
        }
    }

    struct WSABuffer
    {
        public int Length;
        public IntPtr Pointer;
    }

    struct socket_same_handler
    {
        public GCHandle pinnedObj;
        public Action<socket_result> callback;
        public AsyncCallback handler;
    }

    struct socket_handler
    {
        public int currTotal;
        public ArraySegment<byte> buff;
        public Action<socket_result> callback;
        public Action<socket_result> handler;
    }

    struct socket_ptr_handler
    {
        public int currTotal;
        public IntPtr pointer;
        public int size;
        public GCHandle pinnedObj;
        public Action<socket_result> handler;
        public Action<socket_result> callback;
    }

    struct accept_handler
    {
        public socket_tcp socket;
        public AsyncCallback handler;
        public Action<socket_result> callback;
    }

    struct accept_lost_handler
    {
        public socket_tcp socket;
        public Action<socket_result> handler;
    }

    public abstract class socket
    {
        [DllImport("kernel32.dll", CharSet = CharSet.None, ExactSpelling = false, SetLastError = true)]
        static extern int WriteFile(SafeFileHandle handle, IntPtr bytes, int numBytesToWrite, out int numBytesWritten, IntPtr mustBeZero);
        [DllImport("kernel32.dll", CharSet = CharSet.None, ExactSpelling = false, SetLastError = true)]
        static extern int ReadFile(SafeFileHandle handle, IntPtr bytes, int numBytesToRead, out int numBytesRead, IntPtr mustBeZero);
        [DllImport("kernel32.dll", CharSet = CharSet.None, ExactSpelling = false, SetLastError = true)]
        static extern int CancelIoEx(SafeFileHandle handle, IntPtr mustBeZero);

        static readonly Func<UnmanagedMemoryAccessor, SafeBuffer> _getAccessorBuffer = TypeReflection.CreateObjectGetter<UnmanagedMemoryAccessor, SafeBuffer>("_buffer");
        static readonly Func<UnmanagedMemoryStream, SafeBuffer> _getStreamBuffer = TypeReflection.CreateObjectGetter<UnmanagedMemoryStream, SafeBuffer>("_buffer");
        static readonly Func<SafeHandle, IntPtr> _getSafeHandle = TypeReflection.CreateObjectGetter<SafeHandle, IntPtr>("handle");

        static public tuple<bool, int> sync_write(SafeFileHandle handle, IntPtr pointer, long offset, int size)
        {
            int num = 0;
            return new tuple<bool, int>(1 == WriteFile(handle, new IntPtr(pointer.ToInt64() + offset), size, out num, IntPtr.Zero), num);
        }

        static public tuple<bool, int> sync_read(SafeFileHandle handle, IntPtr pointer, long offset, int size)
        {
            int num = 0;
            return new tuple<bool, int>(1 == ReadFile(handle, new IntPtr(pointer.ToInt64() + offset), size, out num, IntPtr.Zero), num);
        }

        static public tuple<bool, int> sync_write(SafeFileHandle handle, byte[] bytes, int offset, int size)
        {
            return sync_write(handle, Marshal.UnsafeAddrOfPinnedArrayElement(bytes, 0), offset, size);
        }

        static public tuple<bool, int> sync_read(SafeFileHandle handle, byte[] bytes, int offset, int size)
        {
            return sync_read(handle, Marshal.UnsafeAddrOfPinnedArrayElement(bytes, 0), offset, size);
        }

        static public tuple<bool, int> sync_write(SafeFileHandle handle, byte[] bytes)
        {
            return sync_write(handle, bytes, 0, bytes.Length);
        }

        static public tuple<bool, int> sync_read(SafeFileHandle handle, byte[] bytes)
        {
            return sync_read(handle, bytes, 0, bytes.Length);
        }

        static public bool cancel_io(SafeFileHandle handle)
        {
            return 1 == CancelIoEx(handle, IntPtr.Zero);
        }

        static public IntPtr get_mmview_ptr(MemoryMappedViewAccessor mmv)
        {
            return _getSafeHandle(_getAccessorBuffer(mmv));
        }

        static public IntPtr get_mmview_ptr(MemoryMappedViewStream mmv)
        {
            return _getSafeHandle(_getStreamBuffer(mmv));
        }

        static public unsafe IntPtr get_string_ptr(string str)
        {
            fixed (char* ptr = str) return new IntPtr(ptr);
        }

        static public unsafe IntPtr get_struct_ptr<T>(ref T str) where T : struct
        {
            fixed (T* ptr = &str) return new IntPtr(ptr);
        }

        static public unsafe IntPtr get_array_ptr<T>(T[] arr) where T : struct
        {
            fixed (T* ptr = arr) return new IntPtr(ptr);
        }

        static public unsafe IntPtr get_array_ptr<T>(T[,] arr) where T : struct
        {
            fixed (T* ptr = arr) return new IntPtr(ptr);
        }

        static public unsafe IntPtr get_array_ptr<T>(T[,,] arr) where T : struct
        {
            fixed (T* ptr = arr) return new IntPtr(ptr);
        }

        static public unsafe IntPtr get_array_ptr<T>(T[,,,] arr) where T : struct
        {
            fixed (T* ptr = arr) return new IntPtr(ptr);
        }

        static public unsafe int get_size<T>() where T : struct
        {
            return sizeof(T);
        }

        static public unsafe void copy_cvt<R, T>(out R dst, ref T src) where R : struct where T : struct
        {
            assert.check(sizeof(R) == sizeof(T), "copy_cvt 转换大小不一致!");
            fixed (T* ptr = &src) dst = *(R*)ptr;
        }

        static public unsafe void copy_cvt<R>(out R dst, IntPtr src) where R : struct
        {
            dst = *(R*)src;
        }

        static public unsafe void copy_cvt<T>(IntPtr dst, ref T src) where T : struct
        {
            *(T*)dst = src;
        }

        protected async_result_wrap<socket_result> _readResult;
        protected async_result_wrap<socket_result> _writeResult;
        socket_handler _readHandler;
        socket_handler _writeHandler;

        protected socket()
        {
            _readResult = new async_result_wrap<socket_result>();
            _writeResult = new async_result_wrap<socket_result>();
            _readHandler.handler = delegate (socket_result tempRes)
            {
                if (tempRes.success)
                {
                    _readHandler.currTotal += tempRes.size;
                    _readHandler.buff = new ArraySegment<byte>(_readHandler.buff.Array, _readHandler.buff.Offset + tempRes.size, _readHandler.buff.Count - tempRes.size);
                    if (0 == _readHandler.buff.Count)
                    {
                        Action<socket_result> callback = _readHandler.callback;
                        _readHandler.buff = default(ArraySegment<byte>);
                        _readHandler.callback = null;
                        functional.catch_invoke(callback, new socket_result(true, _readHandler.currTotal));
                    }
                    else
                    {
                        async_read_same(_readHandler.buff, _readHandler.handler);
                    }
                }
                else
                {
                    Action<socket_result> callback = _readHandler.callback;
                    _readHandler.buff = default(ArraySegment<byte>);
                    _readHandler.callback = null;
                    functional.catch_invoke(callback, new socket_result(false, _readHandler.currTotal, tempRes.ec));
                }
            };
            _writeHandler.handler = delegate (socket_result tempRes)
            {
                if (tempRes.success)
                {
                    _writeHandler.currTotal += tempRes.size;
                    _writeHandler.buff = new ArraySegment<byte>(_writeHandler.buff.Array, _writeHandler.buff.Offset + tempRes.size, _writeHandler.buff.Count - tempRes.size);
                    if (0 == _writeHandler.buff.Count)
                    {
                        Action<socket_result> callback = _writeHandler.callback;
                        _writeHandler.buff = default(ArraySegment<byte>);
                        _writeHandler.callback = null;
                        functional.catch_invoke(callback, new socket_result(true, _writeHandler.currTotal));
                    }
                    else
                    {
                        async_write_same(_writeHandler.buff, _writeHandler.handler);
                    }
                }
                else
                {
                    Action<socket_result> callback = _writeHandler.callback;
                    _writeHandler.buff = default(ArraySegment<byte>);
                    _writeHandler.callback = null;
                    functional.catch_invoke(callback, new socket_result(false, _writeHandler.currTotal, tempRes.ec));
                }
            };
        }

        public abstract void async_read_same(ArraySegment<byte> buff, Action<socket_result> callback);
        public abstract void async_write_same(ArraySegment<byte> buff, Action<socket_result> callback);
        public abstract void close();

        public void async_read_same(byte[] buff, Action<socket_result> callback)
        {
            async_read_same(new ArraySegment<byte>(buff), callback);
        }

        public void async_write_same(byte[] buff, Action<socket_result> callback)
        {
            async_write_same(new ArraySegment<byte>(buff), callback);
        }

        void _async_reads(int currTotal, int currIndex, IList<ArraySegment<byte>> buff, Action<socket_result> callback)
        {
            if (buff.Count == currIndex)
            {
                functional.catch_invoke(callback, new socket_result(true, currTotal));
            }
            else
            {
                async_read(buff[currIndex], delegate (socket_result tempRes)
                {
                    if (tempRes.success)
                    {
                        _async_reads(currTotal + tempRes.size, currIndex + 1, buff, callback);
                    }
                    else
                    {
                        functional.catch_invoke(callback, new socket_result(false, currTotal, tempRes.ec));
                    }
                });
            }
        }

        void _async_reads(int currTotal, int currIndex, IList<byte[]> buff, Action<socket_result> callback)
        {
            if (buff.Count == currIndex)
            {
                functional.catch_invoke(callback, new socket_result(true, currTotal));
            }
            else
            {
                async_read(buff[currIndex], delegate (socket_result tempRes)
                {
                    if (tempRes.success)
                    {
                        _async_reads(currTotal + tempRes.size, currIndex + 1, buff, callback);
                    }
                    else
                    {
                        functional.catch_invoke(callback, new socket_result(false, currTotal, tempRes.ec));
                    }
                });
            }
        }

        public void async_read(ArraySegment<byte> buff, Action<socket_result> callback)
        {
            _readHandler.currTotal = 0;
            _readHandler.buff = buff;
            _readHandler.callback = callback;
            async_read_same(_readHandler.buff, _readHandler.handler);
        }

        public void async_read(byte[] buff, Action<socket_result> callback)
        {
            async_read(new ArraySegment<byte>(buff), callback);
        }

        void _async_writes(int currTotal, int currIndex, IList<ArraySegment<byte>> buff, Action<socket_result> callback)
        {
            if (buff.Count == currIndex)
            {
                functional.catch_invoke(callback, new socket_result(true, currTotal));
            }
            else
            {
                async_write(buff[currIndex], delegate (socket_result tempRes)
                {
                    if (tempRes.success)
                    {
                        _async_writes(currTotal + tempRes.size, currIndex + 1, buff, callback);
                    }
                    else
                    {
                        functional.catch_invoke(callback, new socket_result(false, currTotal, tempRes.ec));
                    }
                });
            }
        }

        void _async_writes(int currTotal, int currIndex, IList<byte[]> buff, Action<socket_result> callback)
        {
            if (buff.Count == currIndex)
            {
                functional.catch_invoke(callback, new socket_result(true, currTotal));
            }
            else
            {
                async_write(buff[currIndex], delegate (socket_result tempRes)
                {
                    if (tempRes.success)
                    {
                        _async_writes(currTotal + tempRes.size, currIndex + 1, buff, callback);
                    }
                    else
                    {
                        functional.catch_invoke(callback, new socket_result(false, currTotal, tempRes.ec));
                    }
                });
            }
        }

        public void async_write(ArraySegment<byte> buff, Action<socket_result> callback)
        {
            _writeHandler.currTotal = 0;
            _writeHandler.buff = buff;
            _writeHandler.callback = callback;
            async_write_same(_writeHandler.buff, _writeHandler.handler);
        }

        public void async_write(byte[] buff, Action<socket_result> callback)
        {
            async_write(new ArraySegment<byte>(buff), callback);
        }

        public ValueTask<socket_result> read_same(ArraySegment<byte> buff)
        {
            generator host = generator.get_this();
            async_read_same(buff, host.async_result(_readResult));
            return host.async_wait(_readResult);
        }

        public ValueTask<socket_result> read_same(byte[] buff)
        {
            generator host = generator.get_this();
            async_read_same(buff, host.async_result(_readResult));
            return host.async_wait(_readResult);
        }

        public ValueTask<socket_result> read(ArraySegment<byte> buff)
        {
            generator host = generator.get_this();
            async_read(buff, host.async_result(_readResult));
            return host.async_wait(_readResult);
        }

        public ValueTask<socket_result> read(byte[] buff)
        {
            generator host = generator.get_this();
            async_read(buff, host.async_result(_readResult));
            return host.async_wait(_readResult);
        }

        public ValueTask<socket_result> reads(IList<byte[]> buff)
        {
            generator host = generator.get_this();
            _async_reads(0, 0, buff, host.async_result(_readResult));
            return host.async_wait(_readResult);
        }

        public ValueTask<socket_result> reads(IList<ArraySegment<byte>> buff)
        {
            generator host = generator.get_this();
            _async_reads(0, 0, buff, host.async_result(_readResult));
            return host.async_wait(_readResult);
        }

        public ValueTask<socket_result> reads(params byte[][] buff)
        {
            generator host = generator.get_this();
            _async_reads(0, 0, buff, host.async_result(_readResult));
            return host.async_wait(_readResult);
        }

        public ValueTask<socket_result> reads(params ArraySegment<byte>[] buff)
        {
            generator host = generator.get_this();
            _async_reads(0, 0, buff, host.async_result(_readResult));
            return host.async_wait(_readResult);
        }

        public ValueTask<socket_result> write_same(ArraySegment<byte> buff)
        {
            generator host = generator.get_this();
            async_write_same(buff, host.async_result(_writeResult));
            return host.async_wait(_writeResult);
        }

        public ValueTask<socket_result> write_same(byte[] buff)
        {
            generator host = generator.get_this();
            async_write_same(buff, host.async_result(_writeResult));
            return host.async_wait(_writeResult);
        }

        public ValueTask<socket_result> write(ArraySegment<byte> buff)
        {
            generator host = generator.get_this();
            async_write(buff, host.async_result(_writeResult));
            return host.async_wait(_writeResult);
        }

        public ValueTask<socket_result> write(byte[] buff)
        {
            generator host = generator.get_this();
            async_write(buff, host.async_result(_writeResult));
            return host.async_wait(_writeResult);
        }

        public ValueTask<socket_result> writes(IList<byte[]> buff)
        {
            generator host = generator.get_this();
            _async_writes(0, 0, buff, host.async_result(_writeResult));
            return host.async_wait(_writeResult);
        }

        public ValueTask<socket_result> writes(IList<ArraySegment<byte>> buff)
        {
            generator host = generator.get_this();
            _async_writes(0, 0, buff, host.async_result(_writeResult));
            return host.async_wait(_writeResult);
        }

        public ValueTask<socket_result> writes(params byte[][] buff)
        {
            generator host = generator.get_this();
            _async_writes(0, 0, buff, host.async_result(_writeResult));
            return host.async_wait(_writeResult);
        }

        public ValueTask<socket_result> writes(params ArraySegment<byte>[] buff)
        {
            generator host = generator.get_this();
            _async_writes(0, 0, buff, host.async_result(_writeResult));
            return host.async_wait(_writeResult);
        }
    }

    public class socket_tcp : socket
    {
        static class SocketAsyncIo
        {
            [DllImport("Ws2_32.dll", CharSet = CharSet.None, ExactSpelling = false, SetLastError = true)]
            static extern SocketError WSASend(IntPtr socketHandle, ref WSABuffer buffer, int bufferCount, out int bytesTransferred, SocketFlags socketFlags, IntPtr overlapped, IntPtr completionRoutine);
            [DllImport("Ws2_32.dll", CharSet = CharSet.None, ExactSpelling = false, SetLastError = true)]
            static extern SocketError WSARecv(IntPtr socketHandle, ref WSABuffer buffer, int bufferCount, out int bytesTransferred, ref SocketFlags socketFlags, IntPtr overlapped, IntPtr completionRoutine);
            [DllImport("Kernel32.dll", CharSet = CharSet.None, ExactSpelling = false, SetLastError = true)]
            static extern int SetFilePointerEx(SafeFileHandle fileHandle, long liDistanceToMove, out long lpNewFilePointer, int dwMoveMethod);
            [DllImport("Kernel32.dll", CharSet = CharSet.None, ExactSpelling = false, SetLastError = true)]
            static extern int GetFileSizeEx(SafeFileHandle fileHandle, out long lpFileSize);
            [DllImport("Mswsock.dll", CharSet = CharSet.None, ExactSpelling = false, SetLastError = true)]
            static extern int TransmitFile(IntPtr socketHandle, SafeFileHandle fileHandle, int nNumberOfBytesToWrite, int nNumberOfBytesPerSend, IntPtr overlapped, IntPtr mustBeZero, int dwFlags);
#if NETCOREAPP
#if NET6_0_OR_GREATER
            static readonly Type _TaskToApm = TypeReflection._systemSocketAss.GetType("System.Threading.Tasks.TaskToApm");
            static readonly Func<Task, AsyncCallback, object, IAsyncResult> _taskBegin = TypeReflection.CreateCall<Func<Task, AsyncCallback, object, IAsyncResult>>(_TaskToApm, "Begin", new Type[] { typeof(Task), typeof(AsyncCallback), typeof(object) });
            static readonly Func<Socket, ThreadPoolBoundHandle> _GetOrAllocateThreadPoolBoundHandle = TypeReflection.CreateCall<Func<Socket, ThreadPoolBoundHandle>>(typeof(Socket), "GetOrAllocateThreadPoolBoundHandle", new Type[] { });

            unsafe class StrongBox : System.Threading.Tasks.Sources.IValueTaskSource<int>
            {
                static readonly IOCompletionCallback IOCPHandler = new IOCompletionCallback(delegate (uint errorCode, uint numBytes, NativeOverlapped* pOVERLAP)
                {
                    StrongBox strongBox = (StrongBox)ThreadPoolBoundHandle.GetNativeOverlappedState(pOVERLAP);
                    strongBox.boundHandle.FreeNativeOverlapped(pOVERLAP);
                    if (0 == errorCode)
                    {
                        strongBox.SetResult((int)numBytes);
                    }
                    else
                    {
                        strongBox.SetException(new SocketException((int)errorCode));
                    }
                });

                private System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore<int> core;
                private ThreadPoolBoundHandle boundHandle;

                public StrongBox(ThreadPoolBoundHandle boundHandle)
                {
                    this.boundHandle = boundHandle;
                }

                public ValueTask<int> GetValueTask()
                {
                    return new ValueTask<int>(this, core.Version);
                }

                public void SetResult(int result)
                {
                    core.SetResult(result);
                }

                public void SetException(Exception exception)
                {
                    core.SetException(exception);
                }

                public int GetResult(short token)
                {
                    try
                    {
                        return core.GetResult(token);
                    }
                    finally
                    {
                        core.Reset();
                    }
                }

                public System.Threading.Tasks.Sources.ValueTaskSourceStatus GetStatus(short token)
                {
                    return core.GetStatus(token);
                }

                public void OnCompleted(Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags)
                {
                    core.OnCompleted(continuation, state, token, flags);
                }

                public IntPtr AllocateNativeOverlapped()
                {
                    return (IntPtr)boundHandle.AllocateNativeOverlapped(PreAllocatedOverlapped.UnsafeCreate(IOCPHandler, this, null));
                }

                public void FreeNativeOverlapped(IntPtr handle)
                {
                    boundHandle.FreeNativeOverlapped((NativeOverlapped*)handle);
                }
            }

            static IntPtr New(Socket socket, out StrongBox strongBox)
            {
                strongBox = new StrongBox(_GetOrAllocateThreadPoolBoundHandle(socket));
                return strongBox.AllocateNativeOverlapped();
            }

            static SocketError CheckState(SocketError lastWin32Error, StrongBox strongBox, AsyncCallback callback, IntPtr handle, int num)
            {
                try
                {
                    if (lastWin32Error != SocketError.Success)
                    {
                        lastWin32Error = (SocketError)Marshal.GetLastWin32Error();
                    }
                    if (lastWin32Error == SocketError.Success || lastWin32Error == SocketError.IOPending)
                    {
                        if (lastWin32Error == SocketError.Success)
                        {
                            strongBox.SetResult(num);
                        }
                        _taskBegin(strongBox.GetValueTask().AsTask(), callback, null);
                        return SocketError.Success;
                    }
                    return lastWin32Error;
                }
                finally
                {
                    if (lastWin32Error != SocketError.IOPending)
                    {
                        strongBox.FreeNativeOverlapped(handle);
                    }
                }
            }

            static public SocketError Send(Socket socket, AsyncCallback callback, ref WSABuffer buffer)
            {
                IntPtr handle = New(socket, out StrongBox strongBox);
                return CheckState(WSASend(socket.Handle, ref buffer, 1, out int num, 0, handle, IntPtr.Zero), strongBox, callback, handle, num);
            }

            static public SocketError Recv(Socket socket, AsyncCallback callback, ref WSABuffer buffer)
            {
                SocketFlags socketFlags = 0;
                IntPtr handle = New(socket, out StrongBox strongBox);
                return CheckState(WSARecv(socket.Handle, ref buffer, 1, out int num, ref socketFlags, handle, IntPtr.Zero), strongBox, callback, handle, num);
            }

            static public SocketError SendFile(Socket socket, AsyncCallback callback, SafeFileHandle fileHandle, long offset, int size)
            {
                if (offset >= 0)
                {
                    if (0 == SetFilePointerEx(fileHandle, offset, out long newOffset, 0) || offset != newOffset)
                    {
                        return SocketError.Fault;
                    }
                }
                IntPtr handle = New(socket, out StrongBox strongBox);
                bool success = 0 != TransmitFile(socket.Handle, fileHandle, size, 0, handle, IntPtr.Zero, 0x20 | 0x04);
                SocketError lastWin32Error = success ? SocketError.Success : SocketError.SocketError;
                return CheckState(lastWin32Error, strongBox, callback, handle, size);
            }
#elif NETCOREAPP3_0_OR_GREATER
            private unsafe delegate NativeOverlapped* GetNativeOverlapped(IAsyncResult _);
            static readonly Type _overlappedType = TypeReflection._systemSocketAss.GetType("System.Net.Sockets.OverlappedAsyncResult");
            static readonly Func<Socket, int> _getCleanedUp = TypeReflection.CreateObjectGetter<Socket, int>("_intCleanedUp");
            static readonly Func<Socket, object, AsyncCallback, IAsyncResult> _newOverlappedAsyncResult = TypeReflection.CreateNew<Func<Socket, object, AsyncCallback, IAsyncResult>>(_overlappedType);
            static readonly Func<IAsyncResult, bool, object> _StartPostingAsyncOp = TypeReflection.CreateCall<Func<IAsyncResult, bool, object>>(_overlappedType, "StartPostingAsyncOp", new Type[] { typeof(bool) });
            static readonly Func<IAsyncResult, bool> _FinishPostingAsyncOp = TypeReflection.CreateCall<Func<IAsyncResult, bool>>(_overlappedType, "FinishPostingAsyncOp", new Type[] { });
            static readonly Func<IAsyncResult, bool, int, SocketError> _ProcessOverlappedResult = TypeReflection.CreateCall<Func<IAsyncResult, bool, int, SocketError>>(_overlappedType, "ProcessOverlappedResult", new Type[] { typeof(bool), typeof(int) });
            static readonly Action<IAsyncResult, object> _SetUnmanagedStructures = TypeReflection.CreateCall<Action<IAsyncResult, object>>(_overlappedType, "SetUnmanagedStructures", new Type[] { typeof(object) });
            static readonly Action<Socket, SocketError> _sockektUpdateStatusAfterSocketError = TypeReflection.CreateCall<Action<Socket, SocketError>>(typeof(Socket), "CheckErrorAndUpdateStatus", new Type[] { typeof(SocketError) });
            static readonly GetNativeOverlapped _GetOverlappedHandle = TypeReflection.CreateCallNoCvt<GetNativeOverlapped>(_overlappedType, "get_DangerousOverlappedPointer", new Type[] { });

            static unsafe IntPtr New(Socket socket, AsyncCallback callback, out IAsyncResult asyncResult)
            {
                asyncResult = _newOverlappedAsyncResult(socket, null, callback);
                _StartPostingAsyncOp(asyncResult, false);
                _SetUnmanagedStructures(asyncResult, null);
                return (IntPtr)_GetOverlappedHandle(asyncResult);
            }

            static public SocketError Send(Socket socket, AsyncCallback callback, ref WSABuffer buffer)
            {
                if (0 != _getCleanedUp(socket))
                {
                    throw new ObjectDisposedException(socket.GetType().FullName);
                }
                SocketError lastWin32Error = WSASend(socket.Handle, ref buffer, 1, out int num, 0, New(socket, callback, out IAsyncResult asyncResult), IntPtr.Zero);
                lastWin32Error = _ProcessOverlappedResult(asyncResult, lastWin32Error == SocketError.Success, num);
                if (lastWin32Error == SocketError.Success || lastWin32Error == SocketError.IOPending)
                {
                    _FinishPostingAsyncOp(asyncResult);
                    return SocketError.Success;
                }
                _sockektUpdateStatusAfterSocketError(socket, lastWin32Error);
                return lastWin32Error;
            }

            static public SocketError Recv(Socket socket, AsyncCallback callback, ref WSABuffer buffer)
            {
                if (0 != _getCleanedUp(socket))
                {
                    throw new ObjectDisposedException(socket.GetType().FullName);
                }
                SocketFlags socketFlags = 0;
                SocketError lastWin32Error = WSARecv(socket.Handle, ref buffer, 1, out int num, ref socketFlags, New(socket, callback, out IAsyncResult asyncResult), IntPtr.Zero);
                lastWin32Error = _ProcessOverlappedResult(asyncResult, lastWin32Error == SocketError.Success, num);
                if (lastWin32Error == SocketError.Success || lastWin32Error == SocketError.IOPending)
                {
                    _FinishPostingAsyncOp(asyncResult);
                    return SocketError.Success;
                }
                _sockektUpdateStatusAfterSocketError(socket, lastWin32Error);
                return lastWin32Error;
            }

            static public SocketError SendFile(Socket socket, AsyncCallback callback, SafeFileHandle fileHandle, long offset, int size)
            {
                if (0 != _getCleanedUp(socket))
                {
                    throw new ObjectDisposedException(socket.GetType().FullName);
                }
                if (offset >= 0)
                {
                    if (0 == SetFilePointerEx(fileHandle, offset, out long newOffset, 0) || offset != newOffset)
                    {
                        return SocketError.Fault;
                    }
                }
                bool success = 0 != TransmitFile(socket.Handle, fileHandle, size, 0, New(socket, callback, out IAsyncResult asyncResult), IntPtr.Zero, 0x20 | 0x04);
                SocketError lastWin32Error = _ProcessOverlappedResult(asyncResult, success, 0);
                if (lastWin32Error == SocketError.Success || lastWin32Error == SocketError.IOPending)
                {
                    _FinishPostingAsyncOp(asyncResult);
                    return SocketError.Success;
                }
                _sockektUpdateStatusAfterSocketError(socket, lastWin32Error);
                return lastWin32Error;
            }
#endif
#else
            static readonly Type _overlappedType = TypeReflection._systemAss.GetType("System.Net.Sockets.OverlappedAsyncResult");
            static readonly Func<Socket, int> _getCleanedUp = TypeReflection.CreateObjectGetter<Socket, int>("m_IntCleanedUp");
            static readonly Func<Socket, object, AsyncCallback, IAsyncResult> _newOverlappedAsyncResult = TypeReflection.CreateNew<Func<Socket, object, AsyncCallback, IAsyncResult>>(_overlappedType);
            static readonly Func<IAsyncResult, bool, object> _StartPostingAsyncOp = TypeReflection.CreateCall<Func<IAsyncResult, bool, object>>(_overlappedType, "StartPostingAsyncOp", new Type[] { typeof(bool) });
            static readonly Func<IAsyncResult, bool> _FinishPostingAsyncOp = TypeReflection.CreateCall<Func<IAsyncResult, bool>>(_overlappedType, "FinishPostingAsyncOp", new Type[] { });
            static readonly Action<IAsyncResult, object> _SetUnmanagedStructures = TypeReflection.CreateCall<Action<IAsyncResult, object>>(_overlappedType, "SetUnmanagedStructures", new Type[] { typeof(object) });
            static readonly Func<IAsyncResult, SafeHandle> _GetOverlappedHandle = TypeReflection.CreateCall<Func<IAsyncResult, SafeHandle>>(_overlappedType, "get_OverlappedHandle", new Type[] { });
            static readonly Func<IAsyncResult, SocketError, SocketError> _CheckAsyncCallOverlappedResult = TypeReflection.CreateCall<Func<IAsyncResult, SocketError, SocketError>>(_overlappedType, "CheckAsyncCallOverlappedResult", new Type[] { typeof(SocketError) });
            static readonly Action<Socket, SocketError> _sockektUpdateStatusAfterSocketError = TypeReflection.CreateCall<Action<Socket, SocketError>>(typeof(Socket), "UpdateStatusAfterSocketError", new Type[] { typeof(SocketError) });

            static IntPtr New(Socket socket, AsyncCallback callback, out IAsyncResult asyncResult)
            {
                asyncResult = _newOverlappedAsyncResult(socket, null, callback);
                _StartPostingAsyncOp(asyncResult, false);
                _SetUnmanagedStructures(asyncResult, null);
                return _GetOverlappedHandle(asyncResult).DangerousGetHandle();
            }

            static public SocketError Send(Socket socket, AsyncCallback callback, ref WSABuffer buffer)
            {
                if (0 != _getCleanedUp(socket))
                {
                    throw new ObjectDisposedException(socket.GetType().FullName);
                }
                SocketError lastWin32Error = WSASend(socket.Handle, ref buffer, 1, out int num, 0, New(socket, callback, out IAsyncResult asyncResult), IntPtr.Zero);
                if (SocketError.Success != lastWin32Error)
                {
                    lastWin32Error = (SocketError)Marshal.GetLastWin32Error();
                }
                lastWin32Error = _CheckAsyncCallOverlappedResult(asyncResult, lastWin32Error);
                if (SocketError.Success == lastWin32Error)
                {
                    _FinishPostingAsyncOp(asyncResult);
                    return SocketError.Success;
                }
                _sockektUpdateStatusAfterSocketError(socket, lastWin32Error);
                return lastWin32Error;
            }

            static public SocketError Recv(Socket socket, AsyncCallback callback, ref WSABuffer buffer)
            {
                if (0 != _getCleanedUp(socket))
                {
                    throw new ObjectDisposedException(socket.GetType().FullName);
                }
                SocketFlags socketFlags = 0;
                SocketError lastWin32Error = WSARecv(socket.Handle, ref buffer, 1, out int num, ref socketFlags, New(socket, callback, out IAsyncResult asyncResult), IntPtr.Zero);
                if (SocketError.Success != lastWin32Error)
                {
                    lastWin32Error = (SocketError)Marshal.GetLastWin32Error();
                }
                lastWin32Error = _CheckAsyncCallOverlappedResult(asyncResult, lastWin32Error);
                if (SocketError.Success == lastWin32Error)
                {
                    _FinishPostingAsyncOp(asyncResult);
                    return SocketError.Success;
                }
                _sockektUpdateStatusAfterSocketError(socket, lastWin32Error);
                return lastWin32Error;
            }

            static public SocketError SendFile(Socket socket, AsyncCallback callback, SafeFileHandle fileHandle, long offset, int size)
            {
                if (0 != _getCleanedUp(socket))
                {
                    throw new ObjectDisposedException(socket.GetType().FullName);
                }
                if (offset >= 0)
                {
                    if (0 == SetFilePointerEx(fileHandle, offset, out long newOffset, 0) || offset != newOffset)
                    {
                        return SocketError.Fault;
                    }
                }
                SocketError lastWin32Error = SocketError.Success;
                if (0 == TransmitFile(socket.Handle, fileHandle, size, 0, New(socket, callback, out IAsyncResult asyncResult), IntPtr.Zero, 0x20 | 0x04))
                {
                    lastWin32Error = (SocketError)Marshal.GetLastWin32Error();
                }
                lastWin32Error = _CheckAsyncCallOverlappedResult(asyncResult, lastWin32Error);
                if (SocketError.Success == lastWin32Error)
                {
                    _FinishPostingAsyncOp(asyncResult);
                    return SocketError.Success;
                }
                _sockektUpdateStatusAfterSocketError(socket, lastWin32Error);
                return lastWin32Error;
            }
#endif
        }

        bool _closed;
        Socket _socket;
        WSABuffer _readBuffer;
        WSABuffer _writeBuffer;
        socket_same_handler _readSameHandler;
        socket_same_handler _writeSameHandler;
        socket_ptr_handler _readPtrHandler;
        socket_ptr_handler _writePtrHandler;

        public socket_tcp()
        {
            _closed = false;
            _socket = null;
            _readSameHandler.handler = delegate (IAsyncResult ar)
            {
                GCHandle pinnedObj = _readSameHandler.pinnedObj;
                Action<socket_result> callback = _readSameHandler.callback;
                _readSameHandler.pinnedObj = default;
                _readSameHandler.callback = null;
                try
                {
                    if (pinnedObj.IsAllocated)
                    {
                        pinnedObj.Free();
                    }
                    int size = _socket.EndReceive(ar);
                    functional.catch_invoke(callback, new socket_result(true, size));
                }
                catch (System.Exception ec)
                {
                    functional.catch_invoke(callback, new socket_result(false, 0, ec));
                }
            };
            _writeSameHandler.handler = delegate (IAsyncResult ar)
            {
                GCHandle pinnedObj = _writeSameHandler.pinnedObj;
                Action<socket_result> callback = _writeSameHandler.callback;
                _writeSameHandler.pinnedObj = default;
                _writeSameHandler.callback = null;
                try
                {
                    if (pinnedObj.IsAllocated)
                    {
                        pinnedObj.Free();
                    }
                    int size = _socket.EndSend(ar);
                    functional.catch_invoke(callback, new socket_result(true, size));
                }
                catch (System.Exception ec)
                {
                    functional.catch_invoke(callback, new socket_result(false, 0, ec));
                }
            };
            _readPtrHandler.handler = delegate (socket_result tempRes)
            {
                if (tempRes.success)
                {
                    _readPtrHandler.currTotal += tempRes.size;
                    _readPtrHandler.pointer += tempRes.size;
                    _readPtrHandler.size -= tempRes.size;
                    if (0 == _readPtrHandler.size)
                    {
                        GCHandle pinnedObj = _readPtrHandler.pinnedObj;
                        Action<socket_result> callback = _readPtrHandler.callback;
                        _readPtrHandler.pinnedObj = default;
                        _readPtrHandler.callback = null;
                        if (pinnedObj.IsAllocated)
                        {
                            pinnedObj.Free();
                        }
                        functional.catch_invoke(callback, new socket_result(true, _readPtrHandler.currTotal));
                    }
                    else
                    {
                        async_read_same(_readPtrHandler.pointer, 0, _readPtrHandler.size, _readPtrHandler.handler);
                    }
                }
                else
                {
                    GCHandle pinnedObj = _readPtrHandler.pinnedObj;
                    Action<socket_result> callback = _readPtrHandler.callback;
                    _readPtrHandler.pinnedObj = default;
                    _readPtrHandler.callback = null;
                    if (pinnedObj.IsAllocated)
                    {
                        pinnedObj.Free();
                    }
                    functional.catch_invoke(callback, new socket_result(false, _readPtrHandler.currTotal, tempRes.ec));
                }
            };
            _writePtrHandler.handler = delegate (socket_result tempRes)
            {
                if (tempRes.success)
                {
                    _writePtrHandler.currTotal += tempRes.size;
                    _writePtrHandler.pointer += tempRes.size;
                    _writePtrHandler.size -= tempRes.size;
                    if (0 == _writePtrHandler.size)
                    {
                        GCHandle pinnedObj = _writePtrHandler.pinnedObj;
                        Action<socket_result> callback = _writePtrHandler.callback;
                        _writePtrHandler.pinnedObj = default;
                        _writePtrHandler.callback = null;
                        if (pinnedObj.IsAllocated)
                        {
                            pinnedObj.Free();
                        }
                        functional.catch_invoke(callback, new socket_result(true, _writePtrHandler.currTotal));
                    }
                    else
                    {
                        async_write_same(_writePtrHandler.pointer, 0, _writePtrHandler.size, _writePtrHandler.handler);
                    }
                }
                else
                {
                    GCHandle pinnedObj = _writePtrHandler.pinnedObj;
                    Action<socket_result> callback = _writePtrHandler.callback;
                    _writePtrHandler.pinnedObj = default;
                    _writePtrHandler.callback = null;
                    if (pinnedObj.IsAllocated)
                    {
                        pinnedObj.Free();
                    }
                    functional.catch_invoke(callback, new socket_result(false, _writePtrHandler.currTotal, tempRes.ec));
                }
            };
        }

        public Socket socket
        {
            get
            {
                return _socket;
            }
        }

        public bool keep_alive(int time, int interval)
        {
            try
            {
                byte[] inArray = new byte[12];
                inArray[0] = 1;
                for (int i = 0; i < 4; i++)
                {
                    inArray[4 + i] = (byte)(time >> (i * 8));
                    inArray[8 + i] = (byte)(interval >> (i * 8));
                }
                return 0 == socket.IOControl(IOControlCode.KeepAliveValues, inArray, null);
            }
            catch (Exception)
            {
                return false;
            }
        }

        public override void close()
        {
            Socket socket = null;
            lock (this)
            {
                if (!_closed)
                {
                    _closed = true;
                    socket = _socket;
                }
            }
            socket?.Close();
        }

        public void async_connect(string ip, int port, Action<socket_result> callback)
        {
            async_connect(ip, port, null, callback);
        }

        public void async_connect(string ip, int port, string localIp, Action<socket_result> callback)
        {
            try
            {
                bool isEmpty = false;
                lock (this) isEmpty = !_closed && null == _socket;
                if (!isEmpty)
                {
                    functional.catch_invoke(callback, new socket_result(false));
                    return;
                }
                IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(ip), port);
                Socket newSocket = new Socket(remoteEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                if (localIp?.Length > 0)
                {
                    newSocket.Bind(new IPEndPoint(IPAddress.Parse(localIp), 0));
                }
                newSocket.BeginConnect(remoteEP, delegate (IAsyncResult ar)
                {
                    try
                    {
                        newSocket.EndConnect(ar);
                        newSocket.NoDelay = true;
                        bool state = false;
                        lock (this)
                        {
                            if (!_closed && null == _socket)
                            {
                                _socket = newSocket;
                                state = true;
                            }
                        }
                        if (!state)
                        {
                            newSocket.Close();
                        }
                        functional.catch_invoke(callback, new socket_result(state));
                    }
                    catch (System.Exception ec)
                    {
                        functional.catch_invoke(callback, new socket_result(false, 0, ec));
                    }
                }, null);
            }
            catch (System.Exception ec)
            {
                close();
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public void async_connect(Socket newSocket, string ip, int port, Action<socket_result> callback)
        {
            try
            {
                bool isEmpty = false;
                lock (this) isEmpty = !_closed && null == _socket;
                if (!isEmpty)
                {
                    functional.catch_invoke(callback, new socket_result(false));
                    return;
                }
                IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(ip), port);
                newSocket.BeginConnect(remoteEP, delegate (IAsyncResult ar)
                {
                    try
                    {
                        newSocket.EndConnect(ar);
                        bool state = false;
                        lock (this)
                        {
                            if (!_closed && null == _socket)
                            {
                                _socket = newSocket;
                                state = true;
                            }
                        }
                        if (!state)
                        {
                            newSocket.Close();
                        }
                        functional.catch_invoke(callback, new socket_result(state));
                    }
                    catch (System.Exception ec)
                    {
                        functional.catch_invoke(callback, new socket_result(false, 0, ec));
                    }
                }, null);
            }
            catch (System.Exception ec)
            {
                close();
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public void async_disconnect(Action<socket_result> callback)
        {
            try
            {
                _socket.BeginDisconnect(false, delegate (IAsyncResult ar)
                {
                    try
                    {
                        _socket.EndDisconnect(ar);
                        functional.catch_invoke(callback, new socket_result(true));
                    }
                    catch (System.Exception ec)
                    {
                        functional.catch_invoke(callback, new socket_result(false, 0, ec));
                    }
                }, null);
            }
            catch (System.Exception ec)
            {
                close();
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public override void async_read_same(ArraySegment<byte> buff, Action<socket_result> callback)
        {
            assert.check(null == _readSameHandler.callback, "重入的 read 操作!");
            try
            {
                _readSameHandler.callback = callback;
                _socket.BeginReceive(buff.Array, buff.Offset, buff.Count, 0, _readSameHandler.handler, null);
            }
            catch (System.Exception ec)
            {
                close();
                _readSameHandler.callback = null;
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public override void async_write_same(ArraySegment<byte> buff, Action<socket_result> callback)
        {
            assert.check(null == _writeSameHandler.callback, "重入的 write 操作!");
            try
            {
                _writeSameHandler.callback = callback;
                _socket.BeginSend(buff.Array, buff.Offset, buff.Count, 0, _writeSameHandler.handler, null);
            }
            catch (System.Exception ec)
            {
                close();
                _writeSameHandler.callback = null;
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public void async_send_file(SafeFileHandle fileHandle, long offset, int size, Action<socket_result> callback, GCHandle pinnedObj = default)
        {
            assert.check(null == _writeSameHandler.callback, "重入的 write 操作!");
            try
            {
                _writeSameHandler.pinnedObj = pinnedObj;
                _writeSameHandler.callback = callback;
                SocketError lastWin32Error = SocketAsyncIo.SendFile(_socket, _writeSameHandler.handler, fileHandle, offset, size);
                if (SocketError.Success != lastWin32Error)
                {
                    throw new SocketException((int)lastWin32Error);
                }
            }
            catch (System.Exception ec)
            {
                close();
                _writeSameHandler.pinnedObj = default;
                _writeSameHandler.callback = null;
                if (pinnedObj.IsAllocated)
                {
                    pinnedObj.Free();
                }
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public void async_read_same(IntPtr pointer, long offset, int size, Action<socket_result> callback, GCHandle pinnedObj = default)
        {
            assert.check(null == _readSameHandler.callback, "重入的 read 操作!");
            try
            {
                if (size == 0)
                {
                    if (pinnedObj.IsAllocated)
                    {
                        pinnedObj.Free();
                    }
                    functional.catch_invoke(callback, new socket_result(true, 0));
                    return;
                }
                _readSameHandler.pinnedObj = pinnedObj;
                _readSameHandler.callback = callback;
                _readBuffer.Length = size;
                _readBuffer.Pointer = new IntPtr(pointer.ToInt64() + offset);
                SocketError lastWin32Error = SocketAsyncIo.Recv(_socket, _readSameHandler.handler, ref _readBuffer);
                if (SocketError.Success != lastWin32Error)
                {
                    throw new SocketException((int)lastWin32Error);
                }
            }
            catch (System.Exception ec)
            {
                close();
                _readSameHandler.pinnedObj = default;
                _readSameHandler.callback = null;
                if (pinnedObj.IsAllocated)
                {
                    pinnedObj.Free();
                }
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public void async_write_same(IntPtr pointer, long offset, int size, Action<socket_result> callback, GCHandle pinnedObj = default)
        {
            assert.check(null == _writeSameHandler.callback, "重入的 write 操作!");
            try
            {
                if (size == 0)
                {
                    if (pinnedObj.IsAllocated)
                    {
                        pinnedObj.Free();
                    }
                    functional.catch_invoke(callback, new socket_result(true, 0));
                    return;
                }
                _writeSameHandler.pinnedObj = pinnedObj;
                _writeSameHandler.callback = callback;
                _writeBuffer.Length = size;
                _writeBuffer.Pointer = new IntPtr(pointer.ToInt64() + offset);
                SocketError lastWin32Error = SocketAsyncIo.Send(_socket, _writeSameHandler.handler, ref _writeBuffer);
                if (SocketError.Success != lastWin32Error)
                {
                    throw new SocketException((int)lastWin32Error);
                }
            }
            catch (System.Exception ec)
            {
                close();
                _writeSameHandler.pinnedObj = default;
                _writeSameHandler.callback = null;
                if (pinnedObj.IsAllocated)
                {
                    pinnedObj.Free();
                }
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public void async_read(IntPtr pointer, long offset, int size, Action<socket_result> callback, GCHandle pinnedObj = default)
        {
            _readPtrHandler.currTotal = 0;
            _readPtrHandler.pointer = new IntPtr(pointer.ToInt64() + offset);
            _readPtrHandler.size = size;
            _readPtrHandler.pinnedObj = pinnedObj;
            _readPtrHandler.callback = callback;
            async_read_same(_readPtrHandler.pointer, 0, _readPtrHandler.size, _readPtrHandler.handler);
        }

        public void async_write(IntPtr pointer, long offset, int size, Action<socket_result> callback, GCHandle pinnedObj = default)
        {
            _writePtrHandler.currTotal = 0;
            _writePtrHandler.pointer = new IntPtr(pointer.ToInt64() + offset);
            _writePtrHandler.size = size;
            _writePtrHandler.pinnedObj = pinnedObj;
            _writePtrHandler.callback = callback;
            async_write_same(_writePtrHandler.pointer, 0, _writePtrHandler.size, _writePtrHandler.handler);
        }

        public ValueTask<socket_result> read_same(IntPtr pointer, long offset, int size, GCHandle pinnedObj = default)
        {
            generator host = generator.get_this();
            async_read_same(pointer, offset, size, host.async_result(_readResult), pinnedObj);
            return host.async_wait(_readResult);
        }

        public ValueTask<socket_result> write_same(IntPtr pointer, long offset, int size, GCHandle pinnedObj = default)
        {
            generator host = generator.get_this();
            async_write_same(pointer, offset, size, host.async_result(_writeResult), pinnedObj);
            return host.async_wait(_writeResult);
        }

        public ValueTask<socket_result> read(IntPtr pointer, long offset, int size, GCHandle pinnedObj = default)
        {
            generator host = generator.get_this();
            async_read(pointer, offset, size, host.async_result(_readResult), pinnedObj);
            return host.async_wait(_readResult);
        }

        public ValueTask<socket_result> write(IntPtr pointer, long offset, int size, GCHandle pinnedObj = default)
        {
            generator host = generator.get_this();
            async_write(pointer, offset, size, host.async_result(_writeResult), pinnedObj);
            return host.async_wait(_writeResult);
        }

        public ValueTask<socket_result> send_file(SafeFileHandle fileHandle, long offset = 0, int size = 0, GCHandle pinnedObj = default)
        {
            generator host = generator.get_this();
            async_send_file(fileHandle, offset, size, host.async_result(_writeResult), pinnedObj);
            return host.async_wait(_writeResult);
        }

        public ValueTask<socket_result> connect(string ip, int port, string localIp = null)
        {
            return generator.async_call((Action<socket_result> callback) => async_connect(ip, port, localIp, callback));
        }

        public ValueTask<socket_result> connect(Socket newSocket, string ip, int port)
        {
            return generator.async_call((Action<socket_result> callback) => async_connect(newSocket, ip, port, callback));
        }

        public ValueTask<socket_result> disconnect()
        {
            return generator.async_call((Action<socket_result> callback) => async_disconnect(callback));
        }

        public class acceptor
        {
            Socket _socket;
            accept_handler _acceptHandler;
            accept_lost_handler _lostHandler;

            public acceptor()
            {
                _socket = null;
                _acceptHandler.socket = null;
                _acceptHandler.callback = null;
                _acceptHandler.handler = delegate (IAsyncResult ar)
                {
                    socket_tcp socket = _acceptHandler.socket;
                    Action<socket_result> callback = _acceptHandler.callback;
                    _acceptHandler.socket = null;
                    _acceptHandler.callback = null;
                    try
                    {
                        Socket newSocket = _socket.EndAccept(ar);
                        newSocket.NoDelay = true;
                        bool state = false;
                        lock (socket)
                        {
                            if (!socket._closed && null == socket._socket)
                            {
                                socket._socket = newSocket;
                                state = true;
                            }
                        }
                        if (!state)
                        {
                            newSocket.Close();
                        }
                        functional.catch_invoke(callback, new socket_result(state));
                    }
                    catch (System.Exception ec)
                    {
                        functional.catch_invoke(callback, new socket_result(false, 0, ec));
                    }
                };
                _lostHandler.handler = delegate (socket_result res)
                {
                    _lostHandler.socket?.close();
                    _lostHandler.socket = null;
                };
            }

            public Socket socket
            {
                get
                {
                    return _socket;
                }
            }

            public bool bind(string ip, int port, int backlog = 1, bool resue = false)
            {
                assert.check(null == _socket, "重复的 bind 操作!");
                try
                {
                    EndPoint localEP = new IPEndPoint(IPAddress.Parse(ip), port);
                    _socket = new Socket(localEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                    _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, resue);
                    _socket.Bind(localEP);
                    _socket.Listen(backlog);
                    return true;
                }
                catch (System.Exception)
                {
                    _socket?.Close();
                    _socket = null;
                }
                return false;
            }

            public void close()
            {
                _socket?.Close();
            }

            public void async_accept(socket_tcp socket, Action<socket_result> callback)
            {
                try
                {
                    bool isEmpty;
                    lock (socket) isEmpty = !socket._closed && null == socket._socket;
                    if (isEmpty)
                    {
                        _acceptHandler.socket = socket;
                        _acceptHandler.callback = callback;
                        _socket.BeginAccept(_acceptHandler.handler, null);
                    }
                    else
                    {
                        functional.catch_invoke(callback, new socket_result(false));
                    }
                }
                catch (System.Exception ec)
                {
                    close();
                    functional.catch_invoke(callback, new socket_result(false, 0, ec));
                }
            }

            public ValueTask<socket_result> accept(socket_tcp sck)
            {
                _lostHandler.socket = sck;
                return generator.async_call((Action<socket_result> callback) => async_accept(sck, callback), _lostHandler.handler);
            }

            public Task unsafe_accept(async_result_wrap<socket_result> res, socket_tcp sck)
            {
                return generator.unsafe_async_call(res, (Action<socket_result> callback) => async_accept(sck, callback));
            }
        }
    }

    struct pipe_same_handler
    {
        public int writeCount;
        public GCHandle pinnedObj;
        public Action<socket_result> callback;
        public AsyncCallback handler;
    }

#if !NETCOREAPP
    public class socket_serial : socket
    {
        SerialPort _socket;
        pipe_same_handler _readSameHandler;
        pipe_same_handler _writeSameHandler;

        public socket_serial(string portName, int baudRate = 9600, Parity parity = Parity.None, int dataBits = 8, StopBits stopBits = StopBits.One)
        {
            _socket = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
            _readSameHandler.pinnedObj = default;
            _readSameHandler.callback = null;
            _readSameHandler.handler = delegate (IAsyncResult ar)
            {
                Action<socket_result> callback = _readSameHandler.callback;
                _readSameHandler.callback = null;
                try
                {
                    int size = _socket.BaseStream.EndRead(ar);
                    functional.catch_invoke(callback, new socket_result(true, size));
                }
                catch (System.Exception ec)
                {
                    functional.catch_invoke(callback, new socket_result(false, 0, ec));
                }
            };
            _writeSameHandler.pinnedObj = default;
            _writeSameHandler.callback = null;
            _writeSameHandler.handler = delegate (IAsyncResult ar)
            {
                int size = _writeSameHandler.writeCount;
                Action<socket_result> callback = _writeSameHandler.callback;
                _writeSameHandler.writeCount = 0;
                _writeSameHandler.callback = null;
                try
                {
                    _socket.BaseStream.EndWrite(ar);
                    functional.catch_invoke(callback, new socket_result(true, size));
                }
                catch (System.Exception ec)
                {
                    functional.catch_invoke(callback, new socket_result(false, 0, ec));
                }
            };
        }

        public SerialPort socket
        {
            get
            {
                return _socket;
            }
        }

        public bool open()
        {
            try
            {
                _socket.Open();
                return true;
            }
            catch (System.Exception) { }
            return false;
        }

        public override void close()
        {
            try
            {
                _socket.Close();
            }
            catch (System.Exception) { }
        }

        public override void async_read_same(ArraySegment<byte> buff, Action<socket_result> callback)
        {
            assert.check(null == _readSameHandler.callback, "重入的 read 操作!");
            try
            {
                _readSameHandler.callback = callback;
                _socket.BaseStream.BeginRead(buff.Array, buff.Offset, buff.Count, _readSameHandler.handler, null);
            }
            catch (System.Exception ec)
            {
                close();
                _readSameHandler.callback = null;
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public override void async_write_same(ArraySegment<byte> buff, Action<socket_result> callback)
        {
            assert.check(null == _writeSameHandler.callback, "重入的 write 操作!");
            try
            {
                _writeSameHandler.writeCount = buff.Count;
                _writeSameHandler.callback = callback;
                _socket.BaseStream.BeginWrite(buff.Array, buff.Offset, buff.Count, _writeSameHandler.handler, null);
            }
            catch (System.Exception ec)
            {
                close();
                _writeSameHandler.writeCount = 0;
                _writeSameHandler.callback = null;
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public void clear_in_buffer()
        {
            try
            {
                _socket.DiscardInBuffer();
            }
            catch (System.Exception) { }
        }

        public void clear_out_buffer()
        {
            try
            {
                _socket.DiscardOutBuffer();
            }
            catch (System.Exception) { }
        }
    }
#endif

    public abstract class socket_pipe : socket
    {
        struct SocketAsyncIo
        {
            [DllImport("kernel32.dll", CharSet = CharSet.None, ExactSpelling = false, SetLastError = true)]
            static extern int WriteFile(SafePipeHandle handle, IntPtr bytes, int numBytesToWrite, IntPtr mustBeZero, IntPtr overlapped);
            [DllImport("kernel32.dll", CharSet = CharSet.None, ExactSpelling = false, SetLastError = true)]
            static extern int ReadFile(SafePipeHandle handle, IntPtr bytes, int numBytesToRead, IntPtr mustBeZero, IntPtr overlapped);
#if NETCOREAPP
#if NET6_0_OR_GREATER
            static readonly Type _TaskToApm = TypeReflection._systemPipeAss.GetType("System.Threading.Tasks.TaskToApm");
            static readonly Func<Task, AsyncCallback, object, IAsyncResult> _taskBegin = TypeReflection.CreateCall<Func<Task, AsyncCallback, object, IAsyncResult>>(_TaskToApm, "Begin", new Type[] { typeof(Task), typeof(AsyncCallback), typeof(object) });
            static readonly Func<PipeStream, ThreadPoolBoundHandle> _GetOrAllocateThreadPoolBoundHandle = TypeReflection.CreateObjectGetter<PipeStream, ThreadPoolBoundHandle>("_threadPoolBinding");

            unsafe class StrongBox : System.Threading.Tasks.Sources.IValueTaskSource<int>
            {
                static readonly IOCompletionCallback IOCPHandler = new IOCompletionCallback(delegate (uint errorCode, uint numBytes, NativeOverlapped* pOVERLAP)
                {
                    StrongBox strongBox = (StrongBox)ThreadPoolBoundHandle.GetNativeOverlappedState(pOVERLAP);
                    strongBox.boundHandle.FreeNativeOverlapped(pOVERLAP);
                    if (0 == errorCode)
                    {
                        strongBox.SetResult((int)numBytes);
                    }
                    else
                    {
                        strongBox.SetException(new SocketException((int)errorCode));
                    }
                });

                private System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore<int> core;
                private ThreadPoolBoundHandle boundHandle;

                public StrongBox(ThreadPoolBoundHandle boundHandle)
                {
                    this.boundHandle = boundHandle;
                }

                public ValueTask<int> GetValueTask()
                {
                    return new ValueTask<int>(this, core.Version);
                }

                public void SetResult(int result)
                {
                    core.SetResult(result);
                }

                public void SetException(Exception exception)
                {
                    core.SetException(exception);
                }

                public int GetResult(short token)
                {
                    try
                    {
                        return core.GetResult(token);
                    }
                    finally
                    {
                        core.Reset();
                    }
                }

                public System.Threading.Tasks.Sources.ValueTaskSourceStatus GetStatus(short token)
                {
                    return core.GetStatus(token);
                }

                public void OnCompleted(Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags)
                {
                    core.OnCompleted(continuation, state, token, flags);
                }

                public IntPtr AllocateNativeOverlapped()
                {
                    return (IntPtr)boundHandle.AllocateNativeOverlapped(PreAllocatedOverlapped.UnsafeCreate(IOCPHandler, this, null));
                }

                public void FreeNativeOverlapped(IntPtr handle)
                {
                    boundHandle.FreeNativeOverlapped((NativeOverlapped*)handle);
                }
            }

            public void Free()
            {
            }

            static IntPtr New(PipeStream socket, out StrongBox strongBox)
            {
                strongBox = new StrongBox(_GetOrAllocateThreadPoolBoundHandle(socket));
                return strongBox.AllocateNativeOverlapped();
            }

            static int CheckState(int state, StrongBox strongBox, AsyncCallback callback, IntPtr handle)
            {
                if (state != 0)
                {
                    return 0;
                }
                int lastWin32Error = Marshal.GetLastWin32Error();
                if ((int)SocketError.Success == lastWin32Error || (int)SocketError.IOPending == lastWin32Error)
                {
                    _taskBegin(strongBox.GetValueTask().AsTask(), callback, null);
                    return 0;
                }
                strongBox.FreeNativeOverlapped(handle);
                return lastWin32Error;
            }

            public int Recv(PipeStream socket, AsyncCallback callback, IntPtr pointer, long offset, int count)
            {
                IntPtr handle = New(socket, out StrongBox strongBox);
                return CheckState(ReadFile(socket.SafePipeHandle, new IntPtr(pointer.ToInt64() + offset), count, IntPtr.Zero, handle), strongBox, callback, handle);
            }

            public int Send(PipeStream socket, AsyncCallback callback, IntPtr pointer, long offset, int count)
            {
                IntPtr handle = New(socket, out StrongBox strongBox);
                return CheckState(WriteFile(socket.SafePipeHandle, new IntPtr(pointer.ToInt64() + offset), count, IntPtr.Zero, handle), strongBox, callback, handle);
            }
#elif NETCOREAPP3_0_OR_GREATER
            private unsafe delegate NativeOverlapped* GetNativeOverlapped(object _);
            static readonly Type _TaskToApm = TypeReflection._systemPipeAss.GetType("System.Threading.Tasks.TaskToApm");
            static readonly Type _ReadWriteCompletionSource = TypeReflection._systemPipeAss.GetType("System.IO.Pipes.ReadWriteCompletionSource");
            static readonly Func<PipeStream, ReadOnlyMemory<byte>, bool, object> _newReadWriteCompletionSource = TypeReflection.CreateNew<Func<PipeStream, ReadOnlyMemory<byte>, bool, object>>(_ReadWriteCompletionSource);
            static readonly GetNativeOverlapped _getOverlappedHandle = TypeReflection.CreateCallNoCvt<GetNativeOverlapped>(_ReadWriteCompletionSource, "get_Overlapped", new Type[] { });
            static readonly Action<object> _ReleaseResources = TypeReflection.CreateCallNoCvt<Action<object>>(_ReadWriteCompletionSource, "ReleaseResources", new Type[] { });
            static readonly Func<object, Task<int>> _getTask = TypeReflection.CreateCallNoCvt<Func<object, Task<int>>>(_ReadWriteCompletionSource, "get_Task", new Type[] { });
            static readonly Func<Task, AsyncCallback, object, IAsyncResult> _taskBegin = TypeReflection.CreateCall<Func<Task, AsyncCallback, object, IAsyncResult>>(_TaskToApm, "Begin", new Type[] { typeof(Task), typeof(AsyncCallback), typeof(object) });

            private object _lastOverlapped;

            public unsafe void Free()
            {
                if (null != _lastOverlapped)
                {
                    _ReleaseResources(_lastOverlapped);
                    _lastOverlapped = null;
                }
            }

            private unsafe IntPtr New(PipeStream socket, bool isWrite)
            {
                _lastOverlapped = _newReadWriteCompletionSource(socket, ReadOnlyMemory<byte>.Empty, isWrite);
                return (IntPtr)_getOverlappedHandle(_lastOverlapped);
            }

            private int CheckState(AsyncCallback callback, int state)
            {
                if (state != 0)
                {
                    _taskBegin(_getTask(_lastOverlapped), callback, null);
                    return 0;
                }
                int lastWin32Error = Marshal.GetLastWin32Error();
                if ((int)SocketError.Success == lastWin32Error || (int)SocketError.IOPending == lastWin32Error)
                {
                    _taskBegin(_getTask(_lastOverlapped), callback, null);
                    return 0;
                }
                Free();
                return lastWin32Error;
            }

            public int Recv(PipeStream socket, AsyncCallback callback, IntPtr pointer, long offset, int count)
            {
                return CheckState(callback, ReadFile(socket.SafePipeHandle, new IntPtr(pointer.ToInt64() + offset), count, IntPtr.Zero, New(socket, false)));
            }

            public int Send(PipeStream socket, AsyncCallback callback, IntPtr pointer, long offset, int count)
            {
                return CheckState(callback, WriteFile(socket.SafePipeHandle, new IntPtr(pointer.ToInt64() + offset), count, IntPtr.Zero, New(socket, true)));
            }
#endif
#else
            static readonly Type _pipeStreamAsyncResultType = TypeReflection._systemCoreAss.GetType("System.IO.Pipes.PipeStreamAsyncResult");
            static readonly Action<object, object> _setHandle = TypeReflection.CreateObjectSetter(_pipeStreamAsyncResultType, "_handle");
            static readonly Action<object, object> _setCallback = TypeReflection.CreateObjectSetter(_pipeStreamAsyncResultType, "_userCallback");
            static readonly Action<object, object> _setIsWrite = TypeReflection.CreateObjectSetter(_pipeStreamAsyncResultType, "_isWrite");
            static readonly Action<object, object> _setWaitHandle = TypeReflection.CreateObjectSetter(_pipeStreamAsyncResultType, "_waitHandle");
            static readonly Action<object, object> _setState = TypeReflection.CreateObjectSetter(typeof(PipeStream), "m_state");
            static readonly Func<PipeStream, IOCompletionCallback> _getIOCallback = TypeReflection.CreateObjectGetter<PipeStream, IOCompletionCallback>("IOCallback");
            static readonly Func<IAsyncResult> _newOverlappedAsyncResult = TypeReflection.CreateNew<Func<IAsyncResult>>(_pipeStreamAsyncResultType);

            private IntPtr _lastOverlapped;

            public unsafe void Free()
            {
                if (_lastOverlapped != IntPtr.Zero)
                {
                    Overlapped.Free((NativeOverlapped*)_lastOverlapped);
                    _lastOverlapped = IntPtr.Zero;
                }
            }

            private unsafe IntPtr New(PipeStream socket, AsyncCallback callback, bool isWrite)
            {
                IAsyncResult asyncResult = _newOverlappedAsyncResult();
                _setHandle(asyncResult, socket.SafePipeHandle);
                _setCallback(asyncResult, callback);
                _setIsWrite(asyncResult, isWrite);
                _setWaitHandle(asyncResult, new ManualResetEvent(false));
                _lastOverlapped = new IntPtr(new Overlapped(0, 0, IntPtr.Zero, asyncResult).Pack(_getIOCallback(socket), null));
                return _lastOverlapped;
            }

            private int CheckState(PipeStream socket, int state)
            {
                if (state != 0)
                {
                    return 0;
                }
                int lastWin32Error = Marshal.GetLastWin32Error();
                if ((int)SocketError.Success == lastWin32Error || (int)SocketError.IOPending == lastWin32Error)
                {
                    return 0;
                }
                _setState(socket, 2);
                Free();
                return lastWin32Error;
            }

            public int Recv(PipeStream socket, AsyncCallback callback, IntPtr pointer, long offset, int count)
            {
                return CheckState(socket, ReadFile(socket.SafePipeHandle, new IntPtr(pointer.ToInt64() + offset), count, IntPtr.Zero, New(socket, callback, false)));
            }

            public int Send(PipeStream socket, AsyncCallback callback, IntPtr pointer, long offset, int count)
            {
                return CheckState(socket, WriteFile(socket.SafePipeHandle, new IntPtr(pointer.ToInt64() + offset), count, IntPtr.Zero, New(socket, callback, true)));
            }
#endif
        }

        protected PipeStream _socket;
        SocketAsyncIo _readAsyncIo;
        SocketAsyncIo _writeAsyncIo;
        pipe_same_handler _readSameHandler;
        pipe_same_handler _writeSameHandler;
        socket_ptr_handler _readPtrHandler;
        socket_ptr_handler _writePtrHandler;

        protected socket_pipe()
        {
            _readAsyncIo = new SocketAsyncIo();
            _writeAsyncIo = new SocketAsyncIo();
            _readSameHandler.pinnedObj = default;
            _readSameHandler.callback = null;
            _readSameHandler.handler = delegate (IAsyncResult ar)
            {
                GCHandle pinnedObj = _readSameHandler.pinnedObj;
                Action<socket_result> callback = _readSameHandler.callback;
                _readSameHandler.pinnedObj = default;
                _readSameHandler.callback = null;
                try
                {
                    _readAsyncIo.Free();
                    if (pinnedObj.IsAllocated)
                    {
                        pinnedObj.Free();
                    }
                    int size = _socket.EndRead(ar);
                    functional.catch_invoke(callback, new socket_result(true, size));
                }
                catch (System.Exception ec)
                {
                    functional.catch_invoke(callback, new socket_result(false, 0, ec));
                }
            };
            _writeSameHandler.pinnedObj = default;
            _writeSameHandler.callback = null;
            _writeSameHandler.handler = delegate (IAsyncResult ar)
            {
                int size = _writeSameHandler.writeCount;
                GCHandle pinnedObj = _writeSameHandler.pinnedObj;
                Action<socket_result> callback = _writeSameHandler.callback;
                _writeSameHandler.writeCount = 0;
                _writeSameHandler.pinnedObj = default;
                _writeSameHandler.callback = null;
                try
                {
                    _writeAsyncIo.Free();
                    if (pinnedObj.IsAllocated)
                    {
                        pinnedObj.Free();
                    }
                    _socket.EndWrite(ar);
                    functional.catch_invoke(callback, new socket_result(true, size));
                }
                catch (System.Exception ec)
                {
                    functional.catch_invoke(callback, new socket_result(false, 0, ec));
                }
            };
            _readPtrHandler.handler = delegate (socket_result tempRes)
            {
                if (tempRes.success)
                {
                    _readPtrHandler.currTotal += tempRes.size;
                    _readPtrHandler.pointer += tempRes.size;
                    _readPtrHandler.size -= tempRes.size;
                    if (0 == _readPtrHandler.size)
                    {
                        GCHandle pinnedObj = _readPtrHandler.pinnedObj;
                        Action<socket_result> callback = _readPtrHandler.callback;
                        _readPtrHandler.pinnedObj = default;
                        _readPtrHandler.callback = null;
                        if (pinnedObj.IsAllocated)
                        {
                            pinnedObj.Free();
                        }
                        functional.catch_invoke(callback, new socket_result(true, _readPtrHandler.currTotal));
                    }
                    else
                    {
                        async_read_same(_readPtrHandler.pointer, 0, _readPtrHandler.size, _readPtrHandler.handler);
                    }
                }
                else
                {
                    GCHandle pinnedObj = _readPtrHandler.pinnedObj;
                    Action<socket_result> callback = _readPtrHandler.callback;
                    _readPtrHandler.pinnedObj = default;
                    _readPtrHandler.callback = null;
                    if (pinnedObj.IsAllocated)
                    {
                        pinnedObj.Free();
                    }
                    functional.catch_invoke(callback, new socket_result(false, _readPtrHandler.currTotal, tempRes.ec));
                }
            };
            _writePtrHandler.handler = delegate (socket_result tempRes)
            {
                if (tempRes.success)
                {
                    _writePtrHandler.currTotal += tempRes.size;
                    _writePtrHandler.pointer += tempRes.size;
                    _writePtrHandler.size -= tempRes.size;
                    if (0 == _writePtrHandler.size)
                    {
                        GCHandle pinnedObj = _writePtrHandler.pinnedObj;
                        Action<socket_result> callback = _writePtrHandler.callback;
                        _writePtrHandler.pinnedObj = default;
                        _writePtrHandler.callback = null;
                        if (pinnedObj.IsAllocated)
                        {
                            pinnedObj.Free();
                        }
                        functional.catch_invoke(callback, new socket_result(true, _writePtrHandler.currTotal));
                    }
                    else
                    {
                        async_write_same(_writePtrHandler.pointer, 0, _writePtrHandler.size, _writePtrHandler.handler);
                    }
                }
                else
                {
                    GCHandle pinnedObj = _writePtrHandler.pinnedObj;
                    Action<socket_result> callback = _writePtrHandler.callback;
                    _writePtrHandler.pinnedObj = default;
                    _writePtrHandler.callback = null;
                    if (pinnedObj.IsAllocated)
                    {
                        pinnedObj.Free();
                    }
                    functional.catch_invoke(callback, new socket_result(false, _writePtrHandler.currTotal, tempRes.ec));
                }
            };
        }

        public override void async_read_same(ArraySegment<byte> buff, Action<socket_result> callback)
        {
            assert.check(null == _readSameHandler.callback, "重入的 read 操作!");
            try
            {
                _readSameHandler.callback = callback;
                _socket.BeginRead(buff.Array, buff.Offset, buff.Count, _readSameHandler.handler, null);
            }
            catch (System.Exception ec)
            {
                close();
                _readSameHandler.callback = null;
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public override void async_write_same(ArraySegment<byte> buff, Action<socket_result> callback)
        {
            assert.check(null == _writeSameHandler.callback, "重入的 write 操作!");
            try
            {
                _writeSameHandler.writeCount = buff.Count;
                _writeSameHandler.callback = callback;
                _socket.BeginWrite(buff.Array, buff.Offset, buff.Count, _writeSameHandler.handler, null);
            }
            catch (System.Exception ec)
            {
                close();
                _writeSameHandler.writeCount = 0;
                _writeSameHandler.callback = null;
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public void async_read_same(IntPtr pointer, long offset, int size, Action<socket_result> callback, GCHandle pinnedObj = default)
        {
            assert.check(null == _readSameHandler.callback, "重入的 read 操作!");
            try
            {
                if (size == 0)
                {
                    if (pinnedObj.IsAllocated)
                    {
                        pinnedObj.Free();
                    }
                    functional.catch_invoke(callback, new socket_result(true, 0));
                    return;
                }
                _readSameHandler.pinnedObj = pinnedObj;
                _readSameHandler.callback = callback;
                int code = _readAsyncIo.Recv(_socket, _readSameHandler.handler, pointer, offset, size);
                if (0 != code)
                {
                    throw new SocketException(code);
                }
            }
            catch (System.Exception ec)
            {
                close();
                _readSameHandler.pinnedObj = default;
                _readSameHandler.callback = null;
                if (pinnedObj.IsAllocated)
                {
                    pinnedObj.Free();
                }
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public void async_write_same(IntPtr pointer, long offset, int size, Action<socket_result> callback, GCHandle pinnedObj = default)
        {
            assert.check(null == _writeSameHandler.callback, "重入的 write 操作!");
            try
            {
                if (size == 0)
                {
                    if (pinnedObj.IsAllocated)
                    {
                        pinnedObj.Free();
                    }
                    functional.catch_invoke(callback, new socket_result(true, 0));
                    return;
                }
                _writeSameHandler.writeCount = size;
                _writeSameHandler.pinnedObj = pinnedObj;
                _writeSameHandler.callback = callback;
                int code = _writeAsyncIo.Send(_socket, _writeSameHandler.handler, pointer, offset, size);
                if (0 != code)
                {
                    throw new SocketException(code);
                }
            }
            catch (System.Exception ec)
            {
                close();
                _writeSameHandler.writeCount = 0;
                _writeSameHandler.pinnedObj = default;
                _writeSameHandler.callback = null;
                if (pinnedObj.IsAllocated)
                {
                    pinnedObj.Free();
                }
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public void async_read(IntPtr pointer, long offset, int size, Action<socket_result> callback, GCHandle pinnedObj = default)
        {
            _readPtrHandler.currTotal = 0;
            _readPtrHandler.pointer = new IntPtr(pointer.ToInt64() + offset);
            _readPtrHandler.size = size;
            _readPtrHandler.pinnedObj = pinnedObj;
            _readPtrHandler.callback = callback;
            async_read_same(_readPtrHandler.pointer, 0, _readPtrHandler.size, _readPtrHandler.handler);
        }

        public void async_write(IntPtr pointer, long offset, int size, Action<socket_result> callback, GCHandle pinnedObj = default)
        {
            _writePtrHandler.currTotal = 0;
            _writePtrHandler.pointer = new IntPtr(pointer.ToInt64() + offset);
            _writePtrHandler.size = size;
            _writePtrHandler.pinnedObj = pinnedObj;
            _writePtrHandler.callback = callback;
            async_write_same(_writePtrHandler.pointer, 0, _writePtrHandler.size, _writePtrHandler.handler);
        }

        public ValueTask<socket_result> read_same(IntPtr pointer, long offset, int size, GCHandle pinnedObj = default)
        {
            generator host = generator.get_this();
            async_read_same(pointer, offset, size, host.async_result(_readResult), pinnedObj);
            return host.async_wait(_readResult);
        }

        public ValueTask<socket_result> write_same(IntPtr pointer, long offset, int size, GCHandle pinnedObj = default)
        {
            generator host = generator.get_this();
            async_write_same(pointer, offset, size, host.async_result(_writeResult), pinnedObj);
            return host.async_wait(_writeResult);
        }

        public ValueTask<socket_result> read(IntPtr pointer, long offset, int size, GCHandle pinnedObj = default)
        {
            generator host = generator.get_this();
            async_read(pointer, offset, size, host.async_result(_readResult), pinnedObj);
            return host.async_wait(_readResult);
        }

        public ValueTask<socket_result> write(IntPtr pointer, long offset, int size, GCHandle pinnedObj = default)
        {
            generator host = generator.get_this();
            async_write(pointer, offset, size, host.async_result(_writeResult), pinnedObj);
            return host.async_wait(_writeResult);
        }
    }

    public class socket_pipe_server : socket_pipe
    {
        readonly string _pipeName;

        public socket_pipe_server(string pipeName, int inBufferSize = 4 * 1024, int outBufferSize = 4 * 1024)
        {
            _pipeName = pipeName;
            _socket = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, inBufferSize, outBufferSize);
        }

        public NamedPipeServerStream socket
        {
            get
            {
                return (NamedPipeServerStream)_socket;
            }
        }

        public override void close()
        {
            try
            {
                ((NamedPipeServerStream)_socket).Disconnect();
            }
            catch (System.Exception) { }
            _socket.Close();
        }

        public async Task<bool> wait_connection(int ms = -1)
        {
            if (_socket.IsConnected)
            {
                return true;
            }
            bool overtime = false;
            async_timer waitTimeout = null;
            if (ms >= 0)
            {
                waitTimeout = new async_timer(generator.self_strand());
                waitTimeout.timeout(ms, delegate ()
                {
                    overtime = true;
                    try
                    {
                        NamedPipeClientStream timedPipe = new NamedPipeClientStream(".", _pipeName);
                        timedPipe.Connect(0);
                        timedPipe.Close();
                    }
                    catch (System.Exception) { }
                });
            }
            try
            {
                await generator.send_task(() => ((NamedPipeServerStream)_socket).WaitForConnection());
            }
            catch (generator.stop_exception)
            {
                waitTimeout?.advance();
                close();
                throw;
            }
            catch (System.Exception)
            {
                waitTimeout?.advance();
                close();
                return false;
            }
            waitTimeout?.cancel();
            if (overtime)
            {
                close();
            }
            return !overtime;
        }
    }

    public class socket_pipe_client : socket_pipe
    {
        public socket_pipe_client(string pipeName, string serverName = ".")
        {
            _socket = new NamedPipeClientStream(serverName, pipeName, PipeDirection.InOut, PipeOptions.Asynchronous);
        }

        public NamedPipeClientStream socket
        {
            get
            {
                return (NamedPipeClientStream)_socket;
            }
        }

        public override void close()
        {
            _socket.Close();
        }

        public bool try_connect(out bool closed)
        {
            closed = false;
            if (_socket.IsConnected)
            {
                return true;
            }
            try
            {
                ((NamedPipeClientStream)_socket).Connect(0);
                return true;
            }
            catch (System.TimeoutException) { }
            catch (System.Exception)
            {
                closed = true;
            }
            return false;
        }

        public async Task<bool> connect(int ms = -1)
        {
            if (0 == ms)
            {
                return try_connect(out bool _);
            }
            long beginTick = system_tick.get_tick_us();
            while (!try_connect(out bool closed))
            {
                if (closed)
                {
                    return false;
                }
                if (ms > 0 && system_tick.get_tick_us() - beginTick >= (long)ms * 1000)
                {
                    return false;
                }
                await generator.sleep(1);
            }
            return true;
        }
    }
}
